package cn.edu.zstu.overlappingdisappear.activity;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Region;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.android.volley.VolleyError;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import cn.edu.zstu.overlappingdisappear.R;
import cn.edu.zstu.overlappingdisappear.api.UserApi;
import cn.edu.zstu.overlappingdisappear.base.App;
import cn.edu.zstu.overlappingdisappear.base.BaseActivity;
import cn.edu.zstu.overlappingdisappear.base.LocalHelper;
import cn.edu.zstu.overlappingdisappear.base.MyApplication;
import cn.edu.zstu.overlappingdisappear.bean.LeverBean;
import cn.edu.zstu.overlappingdisappear.sqlite.ChainDao;
import cn.edu.zstu.overlappingdisappear.view.GridSurfaceView;

/**
 * @Author ZhuMingWei(986990501@qq.com)
 * @Date on 2019/11/10
 * @Version v1.0.0
 * @Company TODO
 * @Describle TODO
 */

public class ChainActivity extends BaseActivity implements View.OnClickListener {

    private String type;
    private ChainDao chainDao;
    private TextView tvTimer;
    private ImageView btnBack;
    private TextView tvLevel;
    private ImageView btnRefresh;
    private GridSurfaceView gsvGoal;
    private GridSurfaceView gsvContent;

    private List<List<Point>> mPaths;
    private List<List<Point>> mGoalPaths;

    private int curDifficult;
    private int curLevel;
    private String initState;
    private String goalState;
    private int record;

    private Timer timer;
    private boolean isStartTimer = false;
    private boolean isPass = false;
    private boolean isPlay = false;

    //去除偏移量
    private static List<List<Point>> deOffset(List<List<Point>> paths) {

        List<List<Point>> results = new ArrayList<>();

        //获取最小偏移量
        Point offset = new Point(100000, 100000);
        for (List<Point> points : paths) {
            for (Point point : points) {
                if (point.x < offset.x) {
                    offset.x = point.x;
                }
                if (point.y < offset.y) {
                    offset.y = point.y;
                }
            }
        }
        for (List<Point> points : paths) {
            List<Point> rePoints = new ArrayList<Point>();
            for (Point point : points) {
                Point p = new Point(point.x, point.y);
                p.x -= offset.x;
                p.y -= offset.y;
                rePoints.add(p);
            }
            results.add(rePoints);
        }
        return results;
    }

    /**
     * 判断移动结果
     *
     * @param bitmapA
     * @param bitmapB
     */
    public static boolean isPathsFit(Bitmap bitmapA, Bitmap bitmapB) {

        int width = bitmapA.getWidth();
        int height = bitmapA.getHeight();

        // 保存所有的像素的数组，图片宽×高
        int[] pixelsA = new int[width * height];
        bitmapA.getPixels(pixelsA, 0, width, 0, 0, width, height);
        int[] pixelsB = new int[width * height];
        bitmapB.getPixels(pixelsB, 0, width, 0, 0, width, height);
        int startA = 0, startB = 0;
        for (int i = 0; i < pixelsA.length; i++) {
            int clr = pixelsA[i];
            int red = (clr & 0x00ff0000) >> 16; // 取高两位
            int green = (clr & 0x0000ff00) >> 8; // 取中两位
            int blue = clr & 0x000000ff; // 取低两位
            int color = Color.rgb(red, green, blue);
            //如果碰到黑色
            if (color != Color.WHITE) {
                startA = i;
                break;
            }
        }
        for (int i = 0; i < pixelsB.length; i++) {
            int clr = pixelsB[i];
            int red = (clr & 0x00ff0000) >> 16; // 取高两位
            int green = (clr & 0x0000ff00) >> 8; // 取中两位
            int blue = clr & 0x000000ff; // 取低两位
            int color = Color.rgb(red, green, blue);
            //如果碰到黑色
            if (color != Color.WHITE) {
                startB = i;
                break;
            }
        }
        for (int i = startA, j = startB; i < pixelsA.length && j < pixelsB.length; i++, j++) {
            if (pixelsA[i] != pixelsB[j]) {
                return false;
            }
        }
        return true;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chain);
        initView();
    }

    private void initView() {
        chainDao = new ChainDao(ChainActivity.this);
        tvTimer = findViewById(R.id.tv_timer);
        btnBack = findViewById(R.id.btn_back);
        tvLevel = findViewById(R.id.tv_level);
        btnRefresh = findViewById(R.id.btn_refresh);
        gsvGoal = findViewById(R.id.gsv_goal);
        gsvContent = findViewById(R.id.gsv_content);
        gsvGoal.isZoom = true;
        gsvGoal.isDrawGrid = true;
        gsvContent.addGesture(true);
        btnBack.setOnClickListener(this);
        btnRefresh.setOnClickListener(this);
        type = getIntent().getStringExtra("TYPE");
        if ("Chain".equals(type)) {
            gsvContent.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    if (!isStartTimer) {
                        if (timer != null)
                            timer.cancel();
                        timer = new Timer("didadida");
                        timer.schedule(new TimerTask() {
                            @Override
                            public void run() {
                                int runTime = 0;
                                try {
                                    while (!isPass) {
                                        runTime++;
                                        final String curT = String.format("%02d", (runTime / 60)) + ":" + String.format("%02d", (runTime % 60));
                                        ChainActivity.this.runOnUiThread(new Runnable() {
                                            @Override
                                            public void run() {
                                                tvTimer.setText(curT);
                                            }
                                        });
                                        if (isPass)
                                            break;
                                        Thread.sleep(1000);
                                    }
                                } catch (Exception e) {

                                }
                                final int finalRunTime = runTime;
                                ChainActivity.this.runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        if (curLevel + 1 > LocalHelper.getCurLevel(curDifficult))
                                            LocalHelper.setCurLevel(curDifficult, curLevel + 1);
                                        if (finalRunTime < record) {
                                            chainDao.updateRecord(curDifficult, curLevel, finalRunTime);
                                            record = finalRunTime;
                                        }
                                        showNextDialog(finalRunTime, record);
                                    }
                                });
                            }
                        }, 0);
                        isStartTimer = true;
                    }
                    gsvContent.onTouchEvent(motionEvent);
                    return true;
                }
            });
            LeverBean leverBean = (LeverBean) getIntent().getSerializableExtra("Lever");
            if (leverBean != null) {
                curDifficult = leverBean.DIFFICULT;
                curLevel = leverBean.LEVER;
                record = leverBean.RECORD;
                tvLevel.setText(curDifficult + "-" + curLevel);
                initState = leverBean.getINIT_STATE();
                mPaths = new Gson().fromJson(initState, new TypeToken<List<List<Point>>>() {
                }.getType());
                goalState = leverBean.getGOAL_STATE();
                mGoalPaths = new Gson().fromJson(goalState, new TypeToken<List<List<Point>>>() {
                }.getType());
                gsvContent.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        gsvContent.addInitStates(mPaths);
                    }
                }, 50);
                gsvGoal.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        gsvGoal.addInitStates(mGoalPaths);
                    }
                }, 50);
            }
            gsvContent.setOnMoveFinishListener(new GridSurfaceView.OnMoveFinishListener() {
                @Override
                public void onMoveFinish(Canvas canvas, List<List<Point>> paths) {

                    List<List<Point>> dePaths = deOffset(paths);
                    List<List<Point>> deMGoalPaths = deOffset(mGoalPaths);

                    //这边直接用canvas画，然后保存
                    Bitmap bitmapA = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
                    Canvas CheckCanvasA = new Canvas(bitmapA);
                    CheckCanvasA.drawColor(Color.WHITE);
                    CheckCanvasA.save();
                    for (int i = 0; i < dePaths.size(); i++) {
                        Path path = new Path();
                        for (int j = 0; j < dePaths.get(i).size(); j++) {
                            if (j == 0)
                                path.moveTo((dePaths.get(i).get(j).x / gsvContent.mBolckWidth * 5), (dePaths.get(i).get(j).y / gsvContent.mBolckWidth * 5));
                            else
                                path.lineTo((dePaths.get(i).get(j).x / gsvContent.mBolckWidth * 5), (dePaths.get(i).get(j).y / gsvContent.mBolckWidth * 5));
                        }
                        path.close();
                        if (i == 0)
                            CheckCanvasA.clipPath(path);
                        else
                            CheckCanvasA.clipPath(path, Region.Op.XOR);
                    }
                    CheckCanvasA.drawColor(Color.BLACK);
                    CheckCanvasA.restore();

                    Bitmap bitmapB = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
                    Canvas CheckCanvasB = new Canvas(bitmapB);
                    CheckCanvasB.drawColor(Color.WHITE);
                    CheckCanvasB.save();
                    for (int i = 0; i < deMGoalPaths.size(); i++) {
                        Path path = new Path();
                        for (int j = 0; j < deMGoalPaths.get(i).size(); j++) {
                            if (j == 0)
                                path.moveTo((deMGoalPaths.get(i).get(j).x * 5), (deMGoalPaths.get(i).get(j).y * 5));
                            else
                                path.lineTo((deMGoalPaths.get(i).get(j).x * 5), (deMGoalPaths.get(i).get(j).y * 5));
                        }
                        path.close();
                        if (i == 0)
                            CheckCanvasB.clipPath(path);
                        else
                            CheckCanvasB.clipPath(path, Region.Op.XOR);
                    }
                    CheckCanvasB.drawColor(Color.BLACK);
                    CheckCanvasB.restore();
                    if (isPathsFit(bitmapA, bitmapB)) {
                        isPass = true;
//                    if(curLevel + 1 > LocalHelper.getCurLevel(curDifficult))
//                        LocalHelper.setCurLevel(curDifficult,curLevel + 1);
//                    showNextDialog(0);
                        //Toast.makeText(ChainActivity.this, "已通关", Toast.LENGTH_LONG).show();
                    }
                }
            });
        } else if ("Match".equals(type)) {
            if (!isStartTimer) {
                if (timer != null)
                    timer.cancel();
                timer = new Timer("didadida");
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        int runTime = 0;
                        try {
                            while (!isPass) {
                                runTime++;
                                final String curT = String.format("%02d", (runTime / 60)) + ":" + String.format("%02d", (runTime % 60));
                                ChainActivity.this.runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        tvTimer.setText(curT);
                                    }
                                });
                                if (isPass)
                                    break;
                                Thread.sleep(1000);
                            }
                        } catch (Exception e) {

                        }
                        final int finalRunTime = runTime;
                        ChainActivity.this.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                UserApi.commitResult(App.Username, App.RoomID, finalRunTime, new UserApi.VolleyStrHandler() {
                                    @Override
                                    public void onErrorResponse(VolleyError error) {
                                        Toast.makeText(MyApplication.getInstance(), "网络连接异常", Toast.LENGTH_LONG).show();
                                    }

                                    @Override
                                    public void onResponse(String responseStr) {
                                        try {
                                            JSONObject reponse = new JSONObject(responseStr);
                                            int status = reponse.getInt("code");
                                            String msg = reponse.getString("msg");
                                            if (status == 1) {
                                                isPlay = false;
                                                showWinDialog();
                                            }
                                        } catch (Exception e) {

                                        }
                                    }
                                });
                            }
                        });
                    }
                }, 0);
                isStartTimer = true;
            }
            tvLevel.setText("");
            initState = App.Room.init;
            mPaths = new Gson().fromJson(initState, new TypeToken<List<List<Point>>>() {
            }.getType());
            goalState = App.Room.goal;
            mGoalPaths = new Gson().fromJson(goalState, new TypeToken<List<List<Point>>>() {
            }.getType());
            gsvContent.postDelayed(new Runnable() {
                @Override
                public void run() {
                    gsvContent.addInitStates(mPaths);
                }
            }, 50);
            gsvGoal.postDelayed(new Runnable() {
                @Override
                public void run() {
                    gsvGoal.addInitStates(mGoalPaths);
                }
            }, 50);
            gsvContent.setOnMoveFinishListener(new GridSurfaceView.OnMoveFinishListener() {
                @Override
                public void onMoveFinish(Canvas canvas, List<List<Point>> paths) {

                    List<List<Point>> dePaths = deOffset(paths);
                    List<List<Point>> deMGoalPaths = deOffset(mGoalPaths);

                    //这边直接用canvas画，然后保存
                    Bitmap bitmapA = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
                    Canvas CheckCanvasA = new Canvas(bitmapA);
                    CheckCanvasA.drawColor(Color.WHITE);
                    CheckCanvasA.save();
                    for (int i = 0; i < dePaths.size(); i++) {
                        Path path = new Path();
                        for (int j = 0; j < dePaths.get(i).size(); j++) {
                            if (j == 0)
                                path.moveTo((dePaths.get(i).get(j).x / gsvContent.mBolckWidth * 5), (dePaths.get(i).get(j).y / gsvContent.mBolckWidth * 5));
                            else
                                path.lineTo((dePaths.get(i).get(j).x / gsvContent.mBolckWidth * 5), (dePaths.get(i).get(j).y / gsvContent.mBolckWidth * 5));
                        }
                        path.close();
                        if (i == 0)
                            CheckCanvasA.clipPath(path);
                        else
                            CheckCanvasA.clipPath(path, Region.Op.XOR);
                    }
                    CheckCanvasA.drawColor(Color.BLACK);
                    CheckCanvasA.restore();

                    Bitmap bitmapB = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
                    Canvas CheckCanvasB = new Canvas(bitmapB);
                    CheckCanvasB.drawColor(Color.WHITE);
                    CheckCanvasB.save();
                    for (int i = 0; i < deMGoalPaths.size(); i++) {
                        Path path = new Path();
                        for (int j = 0; j < deMGoalPaths.get(i).size(); j++) {
                            if (j == 0)
                                path.moveTo((deMGoalPaths.get(i).get(j).x * 5), (deMGoalPaths.get(i).get(j).y * 5));
                            else
                                path.lineTo((deMGoalPaths.get(i).get(j).x * 5), (deMGoalPaths.get(i).get(j).y * 5));
                        }
                        path.close();
                        if (i == 0)
                            CheckCanvasB.clipPath(path);
                        else
                            CheckCanvasB.clipPath(path, Region.Op.XOR);
                    }
                    CheckCanvasB.drawColor(Color.BLACK);
                    CheckCanvasB.restore();
                    if (isPathsFit(bitmapA, bitmapB)) {
                        isPass = true;
                    }
                }
            });
            isPlay = true;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (isPlay){
                        UserApi.searchRoomState(App.RoomID, new UserApi.VolleyStrHandler() {
                            @Override
                            public void onErrorResponse(VolleyError error) {
                                Toast.makeText(MyApplication.getInstance(),"网络连接异常", Toast.LENGTH_LONG).show();
                            }

                            @Override
                            public void onResponse(String responseStr) {
                                try {
                                    JSONObject reponse = new JSONObject(responseStr);
                                    int code = reponse.getInt("code");
                                    String msg=reponse.getString("msg");
                                    if(1 == code){
                                        int status = reponse.getInt("status");
                                        if(3 == status){
                                            if(isPlay){
                                                showLossDialog();
                                                isPlay = false;
                                            }
                                        }
                                    }
                                } catch (JSONException e) {

                                }
                            }
                        });
                        try {
                            Thread.sleep(App.SleepTime);
                        } catch (Exception e){

                        }
                    }
                }
            }).start();
        }
    }

    private void showNextDialog(int runTime, int rcd) {
        final AlertDialog alertNext = new AlertDialog.Builder(ChainActivity.this).create();
        alertNext.show();
        alertNext.getWindow().setContentView(R.layout.dialog_next_level);//重用布局文件

        TextView tv_finishTime = alertNext.getWindow().findViewById(R.id.tv_finish_time);
        TextView tv_record = alertNext.getWindow().findViewById(R.id.tv_record);
        ImageView btn_menu = alertNext.getWindow().findViewById(R.id.btn_menu);
        ImageView btn_again = alertNext.getWindow().findViewById(R.id.btn_again);
        ImageView btn_next = alertNext.getWindow().findViewById(R.id.btn_next);

        tv_finishTime.setText(String.format("%02d", (runTime / 60)) + ":" + String.format("%02d", (runTime % 60)));
        tv_record.setText(String.format("%02d", (rcd / 60)) + ":" + String.format("%02d", (rcd % 60)));
        btn_menu.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                alertNext.dismiss();
                finish();
            }
        });

        btn_again.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                alertNext.dismiss();
                isStartTimer = false;
                isPass = false;
                tvTimer.setText("00:00");
                refresh();
            }
        });

        btn_next.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                LeverBean leverBean = chainDao.queryLevel(curDifficult, curLevel + 1);
                if (leverBean == null) {
                    alertNext.dismiss();
                    return;
                }
                ++curLevel;
                tvLevel.setText(curDifficult + "-" + curLevel);
                initState = leverBean.INIT_STATE;
                record = leverBean.RECORD;
                mPaths = new Gson().fromJson(initState, new TypeToken<List<List<Point>>>() {
                }.getType());
                gsvContent.addInitStates(mPaths);
                goalState = leverBean.GOAL_STATE;
                mGoalPaths = new Gson().fromJson(goalState, new TypeToken<List<List<Point>>>() {
                }.getType());
                gsvGoal.addInitStates(mGoalPaths);
                isStartTimer = false;
                isPass = false;
                tvTimer.setText("00:00");
                alertNext.dismiss();
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        isPlay = false;
        if (chainDao != null)
            chainDao.close();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_back:
                finish();
                break;
            case R.id.btn_refresh:
                refresh();
                break;
        }
    }

    private void refresh() {
        mPaths = new Gson().fromJson(initState, new TypeToken<List<List<Point>>>() {
        }.getType());
        gsvContent.addInitStates(mPaths);
    }

    private void showWinDialog() {
        final AlertDialog alertWin = new AlertDialog.Builder(ChainActivity.this).create();
        alertWin.show();
        alertWin.getWindow().setContentView(R.layout.dialog_win);//重用布局文件
        LinearLayout llContent = alertWin.getWindow().findViewById(R.id.ll_content);
        llContent.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                alertWin.dismiss();
                finish();
            }
        });
    }

    private void showLossDialog() {
        final AlertDialog alertLoss = new AlertDialog.Builder(ChainActivity.this).create();
        alertLoss.show();
        alertLoss.getWindow().setContentView(R.layout.dialog_loss);//重用布局文件
        LinearLayout llContent = alertLoss.getWindow().findViewById(R.id.ll_content);
        llContent.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                alertLoss.dismiss();
                finish();
            }
        });
    }
}
